<template>
  <div class="img-upload-wrap">
    <el-upload
      ref="uploadRef"
      v-model:file-list="myFileList"
      :class="['upload-demo', { hide: isHidden }]"
      :action="actionInfo.uploadUrl"
      :data="actionInfo.data"
      :headers="actionInfo.headers"
      :method="method"
      :multiple="multiple"
      :name="name"
      :is-avatar="isAvatar"
      :show-file-list="showFileList"
      :drag="drag"
      :accept="accept"
      :list-type="listType"
      :disabled="disabled"
      :limit="limit"
      :auto-upload="autoUpload"
      :is-show-tip="isShowTip"
      :before-upload="handleBeforeUpload"
      :on-preview="handlePreview"
      :on-success="handleSuccess"
      :on-error="handleError"
      :on-exceed="handleExceed"
    >
      <template v-if="isAvatar">
        <img v-if="avatarUrl" :src="avatarUrl" class="avatar" />
        <i-ep-plus v-else></i-ep-plus>
      </template>
      <!-- 插槽默认上传按钮，可自定义 -->
      <template v-if="listType !== 'picture-card'">
        <slot>
          <el-button>上传图片</el-button>
        </slot>
      </template>
      <!-- 如果是picture-card，则展示为+ icon -->
      <template v-if="listType === 'picture-card' && !isAvatar">
        <i-ep-plus></i-ep-plus>
      </template>
      <template v-if="listType === 'picture-card' && !isAvatar" #file="{ file }">
        <div>
          <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
          <span class="el-upload-list__item-actions">
            <span class="el-upload-list__item-delete" @click="handleRemove(file, [])">
              <i-ep-delete></i-ep-delete>
            </span>
            <span class="el-upload-list__item-zoomIn" @click="handlePreview(file)">
              <i-ep-zoomIn></i-ep-zoomIn>
            </span>
            <span v-if="isProduct" class="main-picture" @click="setMainPicture(file)">{{
              file.mainPicture ? '主图' : '设为主图'
            }}</span>
          </span>
        </div>
      </template>
      <!-- 上传提示 -->
      <template v-if="isShowTip" #tip>
        <div class="el-upload__tip">
          最多上传{{ limit }}张,格式为{{ accept }},单张小于{{ fileSize
          }}{{ fileSizeUnit }},建议750*750像素的白底正方形图片
        </div>
      </template>
    </el-upload>
    <!-- 预览图片 -->
    <el-image-viewer
      v-if="state.dialogVisible"
      :src="state.previewSrc"
      :url-list="state.previewSrcList"
      fit="cover"
      @close="closeViewer"
    ></el-image-viewer>
  </div>
</template>

<script setup lang="ts" name="imgUpload">
import type { UploadUserFile, UploadProps } from 'element-plus'
import { useProxy } from '@/utils/proxy'
import useUserStore from '@/store/modules/user'
interface Propstype {
  method?: string // 上传的请求方法
  multiple?: boolean // 是否多选
  isAvatar?: boolean // 是否头像，如果是上传头像功能，上传一张后不允许再显示+
  avatarUrl?: string // 头像地址
  name?: string // 上传的文件字段名
  showFileList?: boolean // 是否显示上传文件列表 如果是头像置为false
  drag?: boolean // 是否启用拖拽上传
  accept?: string // 允许上传的文件类型
  listType?: 'text' | 'picture' | 'picture-card' // 文件列表的类型 'text' | 'picture' | 'picture-card'
  disabled?: boolean // 是否禁用上传
  limit?: number // 上传个数限制
  autoUpload?: boolean // 是否自动上传
  isShowTip?: boolean //  是否显示提示
  fileSize?: number // 文件大小
  fileSizeUnit?: 'MB' | 'KB' // 文件大小单位
  fileList?: UploadUserFile[] // 文件列表
  isProduct?: boolean // 是否是商品(设为主图按钮)
}
interface Istate {
  dialogVisible?: boolean
  previewSrc?: string | undefined
  previewSrcList?: string[]
}
const props = withDefaults(defineProps<Propstype>(), {
  method: 'post',
  multiple: false,
  isAvatar: false,
  avatarUrl: '',
  name: 'file',
  showFileList: true,
  drag: false,
  limit: 1,
  accept: '.png,.jpg,.jpeg',
  listType: 'picture-card',
  disabled: false,
  autoUpload: true,
  isShowTip: true,
  fileSize: 5,
  fileSizeUnit: 'MB',
  fileList: [] as any,
  isProduct: false
})
const emits = defineEmits(['handleSuccess', 'handleRemove', 'handleSetMain', 'update:fileList'])
const uploadRef = ref()
const myFileList = computed({
  get() {
    return props.fileList
  },
  set(value) {
    emits('update:fileList', value)
  }
})
const userStore = useUserStore()
const { proxy } = useProxy()
const state = reactive<Istate>({
  dialogVisible: false,
  previewSrc: '',
  previewSrcList: []
})
const isHidden = computed(() => {
  if (props.fileList && props.fileList.length >= props.limit) {
    return true
  } else {
    return false
  }
})
const actionInfo = reactive<any>({
  uploadUrl: '',
  cdnDomainName: '',
  headers: {
    token: ''
  },
  data: {
    key: '',
    token: '', // 七牛云token
    data: {}
  }
})
const getQiniuInfo = (_res: any) => {
  actionInfo.uploadUrl = _res.uploadUrl
  actionInfo.headers.token = _res.qiniuToken
  actionInfo.data.token = _res.qiniuToken
  actionInfo.cdnDomainName = _res.cdnDomainName
}
const handleBeforeUpload: UploadProps['beforeUpload'] = (uploadFile): any => {
  // 校验文件格式
  let accepts = props.accept
  if (accepts.length) {
    const fileName = uploadFile.name.split('.')
    const fileExt = fileName[fileName.length - 1]
    const isTypeOk = props.accept.indexOf(fileExt) >= 0
    if (!isTypeOk) {
      proxy.$message.msgError(`文件格式不正确, 请上传${props.accept}格式文件!`)
      return false
    }
  }
  // 校验文件大小
  if (uploadFile.size) {
    let size = props.fileSizeUnit == 'MB' ? uploadFile.size / 1024 / 1024 : uploadFile.size / 1024
    if (size > props.fileSize) {
      proxy.$message.msgError(`请上传大小不超过 ${props.fileSize} ${props.fileSizeUnit}的文件`)
      return false
    }
  }
  actionInfo.data.data = uploadFile
  actionInfo.data.key = uploadFile.uid
}
// 预览图片
const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
  state.previewSrcList = []
  state.dialogVisible = true
  state.previewSrcList.push(uploadFile.url!)
  state.previewSrc = uploadFile.url!
}
// 设为主图
const setMainPicture = (file: any) => {
  if (file.mainPicture) return
  let index = props.fileList.map((v) => v.uid).indexOf(file.uid)
  emits('handleSetMain', index)
}
const closeViewer = () => {
  state.dialogVisible = false
}
const handleRemove: UploadProps['onRemove'] = (uploadFile) => {
  if (props.showFileList) {
    uploadRef.value.handleRemove(uploadFile)
    let index = props.fileList.map((v) => v.uid).indexOf(uploadFile.uid)
    emits('handleRemove', index)
  } else {
    emits('handleRemove', uploadFile.uid)
  }
}
const handleSuccess: UploadProps['onSuccess'] = (response, uploadFile, fileList): any => {
  const imgUrl = `${actionInfo.cdnDomainName}/${response.key}`
  if (props.showFileList) {
    uploadFile.url = imgUrl
    emits('handleSuccess', { uid: uploadFile.uid, url: imgUrl })
  } else {
    emits('handleSuccess', imgUrl)
  }
}
const handleError: UploadProps['onError'] = (uploadFile, fileList) => {
  proxy.$message.msgError('上传失败，请重新上传!！')
}
const handleExceed = () => {
  proxy.$message.msgWarning(`上传文件数量不能超过 ${props.limit} 个!`)
}
onMounted(() => {
  userStore.getQiniu().then((res) => {
    getQiniuInfo(res)
  })
})
</script>

<style scoped lang="scss">
.el-upload__tip {
  font-size: 13px;
  color: #999999;
}
.hide {
  :deep(.el-upload--picture-card) {
    display: none;
  }
}
.upload-demo {
  :deep(.el-upload-list) {
    // 图片列表大小
    .el-upload-list__item {
      width: 100px;
      height: 100px;
      border-radius: 6px;
    }
  }
  // picture-card格式icon大小
  :deep(.el-upload) {
    width: 100px;
    height: 100px;
    border-radius: 6px;
  }
  .avatar {
    width: 100px;
    height: 100px;
    border-radius: 6px;
    display: block;
  }
}
.tip-color {
  color: #f56c6c;
}
.main-picture {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  display: inline-block !important;
  height: 24px;
  background-color: #558df7;
  margin-left: 0px !important;
  text-align: center;
  line-height: 24px;
  font-size: 12px;
}
</style>
